home *** CD-ROM | disk | FTP | other *** search
- {AdnMod 0.2 by Beta/Adrenalin.
- GUS only
- Thanks to:
- flap / Capacala for sending me "some" info
- Mark Feldham for PCGPE
- Mark Dixon for his GUS669 source
- Thunder for excellent info about MODs
- Tran & Joshua C. Jensen for releasing ultradox
-
- Greets:
- Wihannes / Nordic vision
- Solar / Hysteria
- Psyko / Acidface software
- TOP4.ZIP
- All users of Metropoli & Starport
- }
- unit modunit;
- interface
- uses dos;
-
- const
- maxchn = 8; {max # of channels in mod. Lower this, if you run out
- of memory}
- amp_vol : byte = 14; {amplifying volume. Increasing by one doubles
- the volume}
-
- def_pan : byte = 4; {default panning. 0-7}
-
- max_per = 1000; {Max & min period for Amiga limits}
- min_per = 20; {not implemented anymore coz of extra octaves}
- Base : word = $200; {GUS address}
-
- mod_error : word = 0;
- {0 = no error
- 1 = wrong number of channels
- 2 = load error
- 3 = out of pattern memory
- 255 = other error}
-
- per_table : array[0..15,1..48 ] of word = (
- (856,808,762,720,678,640,604,570,538,508,480,453,
- 428,404,381,360,339,320,302,285,269,254,240,226,
- 214,202,190,180,170,160,151,143,135,127,120,113,
- 107,101,95,90,85,80,75,71,67,63,60,56),
-
- (850,802,757,715,674,637,601,567,535,505,477,450,{ : C-1 to B-1 Finetune +1}
- 425,401,379,357,337,318,300,284,268,253,239,225, { : C-2 to B-2 Finetune +1}
- 213,201,189,179,169,159,150,142,134,126,119,113, { : C-3 to B-3 Finetune +1}
- 106,100,94,89,84,79,75,71,67,83,59,56), { : C-4 to B-4 Finetune +1}
-
-
- (844,796,752,709,670,632,597,563,532,502,474,447,{ : C-1 to B-1 Finetune +2}
- 422,398,376,355,335,316,298,282,266,251,237,224, { : C-2 to B-2 Finetune +2}
- 211,199,188,177,167,158,149,141,133,125,118,112, { : C-3 to B-3 Finetune +2}
- 105, 99, 94, 88, 83, 79, 74, 70, 66, 62, 59, 56),{ : C-4 to B-4 Finetune +2}
-
- (838,791,746,704,665,628,592,559,528,498,470,444,{ : C-1 to B-1 Finetune +3}
- 419,395,373,352,332,314,296,280,264,249,235,222, { : C-2 to B-2 Finetune +3}
- 209,198,187,176,166,157,148,140,132,125,118,111, { : C-3 to B-3 Finetune +3}
- 104, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59, 55),{ : C-4 to B-4 Finetune +3}
-
- (832,785,741,699,660,623,588,555,524,495,467,441,{ : C-1 to B-1 Finetune +4}
- 416,392,370,350,330,312,294,278,262,247,233,220, { : C-2 to B-2 Finetune +4}
- 208,196,185,175,165,156,147,139,131,124,117,110, { : C-3 to B-3 Finetune +4}
- 104, 98, 92, 87, 82, 78, 73, 69, 65, 62, 58, 55), {; C-4 to B-4 Finetune +4}
-
- (826,779,736,694,655,619,584,551,520,491,463,437,{ : C-1 to B-1 Finetune +5}
- 413,390,368,347,328,309,292,276,260,245,232,219, { : C-2 to B-2 Finetune +5}
- 206,195,184,174,164,155,146,138,130,123,116,109, { : C-3 to B-3 Finetune +5}
- 103, 97, 92, 87, 82, 77, 73, 69, 65, 61, 58, 54),{ ; C-4 to B-4 Finetune +5}
-
- (820,774,730,689,651,614,580,547,516,487,460,434,{ : C-1 to B-1 Finetune +6}
- 410,387,365,345,325,307,290,274,258,244,230,217, { : C-2 to B-2 Finetune +6}
- 205,193,183,172,163,154,145,137,129,122,115,109, { : C-3 to B-3 Finetune +6}
- 102, 96, 91, 86, 81, 77, 72, 68, 64, 61, 57, 54),{ : C-4 to B-4 Finetune +6}
-
- (814,768,725,684,646,610,575,543,513,484,457,431,{ : C-1 to B-1 Finetune +7}
- 407,384,363,342,323,305,288,272,256,242,228,216, { : C-2 to B-2 Finetune +7}
- 204,192,181,171,161,152,144,136,128,121,114,108, { : C-3 to B-3 Finetune +7}
- 102, 96, 90, 85, 80, 76, 72, 68, 64, 60, 57, 54),{ : C-4 to B-4 Finetune +7}
-
- (907,856,808,762,720,678,640,604,570,538,504,480,{ : C-1 to B-1 Finetune -8 }
- 453,428,404,381,360,339,320,302,285,269,254,240, { : C-2 to B-2 Finetune -8 }
- 226,214,202,190,180,170,160,151,143,135,127,120, { : C-3 to B-3 Finetune -8 }
- 113,107,101, 95, 90, 85, 80, 75, 71, 67, 63, 60),{ : C-4 to B-4 Finetune -8}
-
-
- (900,850,802,757,715,675,636,601,567,535,505,477,{ : C-1 to B-1 Finetune -7 }
- 450,425,401,379,357,337,318,300,284,268,253,238, { : C-2 to B-2 Finetune -7 }
- 225,212,200,189,179,169,159,150,142,134,126,119, { : C-3 to B-3 Finetune -7 }
- 112,106,100, 94, 89, 84, 79, 75, 71, 67, 63, 59),{ : C-4 to B-4 Finetune -7}
-
- (894,844,796,752,709,670,632,597,563,532,502,474,{ : C-1 to B-1 Finetune -6 }
- 447,422,398,376,355,335,316,298,282,266,251,237, { : C-2 to B-2 Finetune -6 }
- 223,211,199,188,177,167,158,149,141,133,125,118, { : C-3 to B-3 Finetune -6 }
- 111,105, 99, 94, 88, 83, 79, 74, 70, 66, 62, 59),{ : C-4 to B-4 Finetune -6}
-
- (887,838,791,746,704,665,628,592,559,528,498,470,{ : C-1 to B-1 Finetune -5 }
- 444,419,395,373,352,332,314,296,280,264,249,235, { : C-2 to B-2 Finetune -5 }
- 222,209,198,187,176,166,157,148,140,132,125,118, { : C-3 to B-3 Finetune -5 }
- 111,104, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59),{ : C-4 to B-4 Finetune -5}
-
- (881,832,785,741,699,660,623,588,555,524,494,467,{ : C-1 to B-1 Finetune -4 }
- 441,416,392,370,350,330,312,294,278,262,247,233, { : C-2 to B-2 Finetune -4 }
- 220,208,196,185,175,165,156,147,139,131,123,117, { : C-3 to B-3 Finetune -4 }
- 110,104, 98, 92, 87, 82, 78, 73, 69, 65, 61, 58),{ C-4 to H-4 Finetune -4}
-
- (875,826,779,736,694,655,619,584,551,520,491,463,{ : C-1 to B-1 Finetune -3 }
- 437,413,390,368,347,338,309,292,276,260,245,232, { : C-2 to B-2 Finetune -3 }
- 219,206,195,184,174,164,155,146,138,130,123,116, { : C-3 to B-3 Finetune -3 }
- 109,103, 97, 92, 87, 82, 77, 73, 69, 65, 61, 58),{ C-4 to H-4 Finetune -3}
-
- (868,820,774,730,689,651,614,580,547,516,487,460,{ : C-1 to B-1 Finetune -2 }
- 434,410,387,365,345,325,307,290,274,258,244,230, { : C-2 to B-2 Finetune -2 }
- 217,205,193,183,172,163,154,145,137,129,122,115, { : C-3 to B-3 Finetune -2 }
- 108,102, 96, 91, 86, 81, 77, 72, 68, 64, 61, 57),{ C-4 to H-4 Finetune -2}
-
- (862,814,768,725,684,646,610,575,543,513,484,457,{ : C-1 to B-1 Finetune -1 }
- 431,407,384,363,342,323,305,288,272,256,242,228, { : C-2 to B-2 Finetune -1 }
- 216,203,192,181,171,161,152,144,136,128,121,114, { : C-3 to B-3 Finetune -1}
- 108,101, 96, 90, 85, 80, 76, 72, 68, 64, 60, 57));{ C-4 to H-4 Finetune -1}
-
- gusvol : array[0..64] of word = {volume table}
-
- (0,1750,2503,2701,2741,2781,2944,2964,2981,
- 3000,3017,3034,3052,3070,3207,3215,3224,
-
- 3232,3240,3248,3256,3263,3271,3279,3287,
- 3294,3303,3310,3317,3325,3458,3462,3466,
-
- 3469,3473,3478,3481,3484,3489,3492,3495,
- 3499,3502,3506,3509,3513,3517,3520,3524,
-
- 3528,3532,3534,3538,3543,3545,3549,3552,
- 3556,3558,3563,3565,3570,3573,3577,3580);
-
- vib_tbl : array[0..2,0..63] of shortint =
- ((0,6,12,19,24,30,36,41,45,49,53,56,59,61,63,64,
- 64,64,63,61,59,56,53,49,45,41,36,30,24,19,12,6,
- 0,-6,-12,-19,-24,-30,-36,-41,-45,-49,-53,-56,-59,-61,-63,-64,
- -64,-64,-63,-61,-59,-56,-53,-49,-45,-41,-36,-30,-24,-19,-12,-6),
- (-63,-61,-59,-57,-55,-53,-51,-49,-47,-45,-43,-41,-39,-37,-35,-33,
- -31,-29,-27,-25,-23,-21,-19,-17,-15,-13,-11,-9,-7,-5,-3,-1,
- 1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,
- 33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63),
- (-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
- -64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,-64,
- 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
- 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64));
-
-
- type
- t_memarray = array[0..2000] of word;
- t_channel = record
- Vol : byte; {current volume 0-64}
- note : byte; {current note 1(C-1) to 48(B-4)}
- Per,dper : word; {period & dest. period for tone portamentos}
- Sample : byte; {current sample}
- Pan : byte; {panning}
- fx,fxdata : byte;
- fx_sl2,fx_vib : byte; {slide to & vibrato fx-data}
- vib_wave : byte; {vibrato waveform}
- vib_cnt : byte; {vibrato counter}
- trig_cnt : byte; {retrig counter}
- arp1,arp2, {arpeggio params}
- arp_cnt : byte; {arpeggio counter}
- start_fx : byte; {tick to start do_fx for channel}
- on : byte; {0 = channel is muted}
- bar : byte; {volume bar}
- hit : byte;
- no_fx : byte {1 = do not get new fx}
- end;
- t_sample = record
- Name : array[1..40] of char;
- Addr : longint; {address in GUS mem}
- Length : word;
- LoopStart,
- LoopEnd : word;
- ftune : byte;
- Volume : byte;
- end;
- t_note = record
- per : word;
- note,
- sample,
- fx,
- fxdata : byte;
- end;
- t_row = array[0..maxchn-1] of t_note;
- t_pattern = array[0..63] of t_row;
- p_pattern = ^t_pattern;
-
- mod_header = record
- name : string[20];
- Length : byte;
- tag : array[0..3] of char; {M.K.}
- chns : byte; {4..12}
- samples : byte; {15 / 31}
- end;
-
- var
- gus_addr : array[0..32] of longint;
- periods : array[0..1100] of word;
- channels : array[0..maxchn-1] of t_channel;
- samples : array[0..32] of t_sample;
- patterns : array[0..128] of p_pattern;
- orders : array[0..255] of byte; {order list}
- max_ptn : word; {# patterns in mod}
- cur_ptn,cur_row,cur_tick : byte;
- new_ptn,new_row,jump : byte; {used in jumps}
- speed,nspeed,tempo : byte;
- vblank : boolean; {true = do not use bpm tempos}
-
- header : mod_header;
- top_addr : longint; {Next free address in GUS mem}
-
- time_counter : longint; {For syncing with demos. Increments
- every 1/18.2 seconds}
- time_counter2 : longint; {Increments every tick}
- vrt_flag : byte; {if 1 then vertical retrace happened}
-
- Procedure GUSDelay;
- Function VoicePos( V : Byte) : Longint;
- Function GUSPeek(Loc : Longint) : Byte;
- Procedure GUSPoke(Loc : Longint; B : Byte);
- Function GUSProbe(adr : word) : Boolean;
- Procedure GUSFind;
- Function GUSFindMem : Longint;
- Procedure GUSSetFreq( V : Byte; hz : Word);
- Procedure GUSVoiceControl( V, B : Byte);
- Procedure GUSSetBalance( V, Bal : Byte);
- Procedure GUSSetVolume( V : Byte; Vol : Word);
- Procedure GUSSetLoopMode( V : Byte);
- Procedure GUSStopVoice( V : Byte);
- Procedure GUSPlayVoice( V, Mode : Byte;VBegin, VStart, VEnd : Longint);
- procedure gusrelvoice(v : byte);
- procedure GusSetOfs(v : byte;vbegin : longint);
- Procedure GUSReset;
- procedure gusdeinit;
-
- procedure updatenotes;
- procedure start_playing;
- procedure stop_playing;
- procedure set_timer(ticks : word);
- procedure init_mod;
- procedure free_mod;
- procedure load_mod(s : string;debug : boolean);
-
-
- implementation
-
- var
- oldint : procedure;
- int_tick,o_int_tick : word;
- int_rate : word;
-
- gus_bank : longint;
-
- misc_buf : array[0..5000] of byte; {buffer used while loading mod}
- misc_buf2 : ^t_memarray; {points to misc_buf}
-
- {$i gus.inc}
-
- {$s-}
- procedure get_notes;
- var
- chn : byte;
- ptn : byte;
- org_sam,sam,note : byte;
- st_ofs : longint;
- per,dper,vol,freq : word;
- _fx,_fxdata : byte;
- mute: byte;
- _ptn : p_pattern;
-
- procedure prefx;
- var
- w : word;
- _efxdata : byte;
- begin
- case _fx of
- 9 : begin
- w := _fxdata*$100;
- st_ofs := w;
- channels[chn].no_fx := 1;
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- end;
- $c : begin
- if _fxdata > 64 then _fxdata := 64;
- vol := _fxdata;
- end;
- $e : begin
- _efxdata := _fxdata and 15;
- case _fxdata shr 4 of
- 4 : begin
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- if _efxdata and 3 < 3 then channels[chn].vib_wave := _efxdata
- else channels[chn].vib_wave := 0 or (_efxdata and 4);
- end;
- $c : if _efxdata and 15 = 0 then begin
- mute := 1;
- gusstopvoice(chn+1);
- end;
- $d : if _efxdata > 0 then mute := 2
- else mute := 0;
- end;
- end;
- end;
- end;
-
- begin
- ptn := orders[cur_ptn];
- for chn := 0 to header.chns-1 do begin
- if channels[chn].fx = 0 then begin
- sam := channels[chn].sample;
- per := per_table[samples[sam].ftune,
- channels[chn].note];
- gussetfreq(chn+1,periods[per]);
- end;
- channels[chn].hit := 0;
- if ((patterns[ptn]^[cur_row,chn].per > 0) or
- (patterns[ptn]^[cur_row,chn].sample > 0)) then begin
- mute := 1;
- vol := channels[chn].vol;
- per := channels[chn].per;
- note := channels[chn].note;
- freq := periods[channels[chn].per];
- _fx := patterns[ptn]^[cur_row,chn].fx;
- _fxdata := patterns[ptn]^[cur_row,chn].fxdata;
- org_sam := patterns[ptn]^[cur_row,chn].sample;
- channels[chn].start_fx := 0;
- channels[chn].trig_cnt := 0;
- if org_sam = 0 then begin
- sam := channels[chn].sample;
- end
- else begin
- sam := org_sam;
- end;
- if (_fx = 3) or (_fx = 5) then begin {port to/port to&vol slide}
- mute := 1; {dont restart sample}
- if patterns[ptn]^[cur_row,chn].note > 0 then begin
- note := patterns[ptn]^[cur_row,chn].note;
- dper := per_table[samples[sam].ftune,note];
- if dper > max_per then dper := max_per;
- if dper < min_per then dper := min_per;
- channels[chn].dper := dper;
- end;
- end
- else if patterns[ptn]^[cur_row,chn].per > 0 then begin
- if patterns[ptn]^[cur_row,chn].note > 0 then begin
- note := patterns[ptn]^[cur_row,chn].note;
- per := per_table[samples[sam].ftune,note];
- end
- else if patterns[ptn]^[cur_row,chn].per > 0 then
- per := patterns[ptn]^[cur_row,chn].per;
-
- if per > max_per then per := max_per;
- if per < min_per then per := min_per;
- channels[chn].dper := per;
- channels[chn].per := per;
- freq := periods[per];
- mute := 0;
- end;
- if org_sam > 0 then begin {should I reset volume}
- vol := samples[sam].volume;
- if channels[chn].sample <> org_sam then mute := 0;
- end;
- if samples[sam].length > 0 then st_ofs := 2;
- {coz first 2 bytes = amiga loopinfo, discard them}
- channels[chn].no_fx := 0;
- prefx;
- channels[chn].vol := vol;
- channels[chn].note := note;
- if channels[chn].vib_wave and 4 = 0 then channels[chn].vib_cnt := 0;
- channels[chn].sample := sam;
- channels[chn].bar := channels[chn].vol;
- vol := gusvol[vol]*amp_vol;
- if channels[chn].on = 0 then mute := 1;
- if mute = 0 then begin
- channels[chn].hit := 1;
- gussetbalance(chn+1,channels[chn].pan);
- if (samples[sam].loopend > 2) then
- gusplayall(chn+1,8,gus_addr[sam]+st_ofs,
- gus_addr[sam]+samples[sam].loopstart,
- gus_addr[sam]+samples[sam].loopend,freq,vol)
- else gusplayall(chn+1,0,gus_addr[sam]+st_ofs,
- gus_addr[sam]+st_ofs,
- gus_addr[sam]+samples[sam].length,freq,vol);
- end
- else if (channels[chn].on = 1) and (mute=1) then gussetvolume(chn+1,vol);
- end;
- end;
- end;
-
- procedure get_fx;
- var
- chn,ptn : byte;
- _fx,_fxdata : byte;
- _efx,_efxdata : byte;
- per : word;
- b : byte;
- w : word;
-
- begin
- ptn := orders[cur_ptn];
- new_ptn := cur_ptn;
- new_row := cur_row;
- jump := 0;
- for chn := 0 to header.chns-1 do
- if channels[chn].no_fx = 0 then begin
- channels[chn].start_fx := 0;
- channels[chn].fx := 255;
- _fx := patterns[ptn]^[cur_row,chn].fx;
- _fxdata := patterns[ptn]^[cur_row,chn].fxdata;
- case _fx of
- 0 : if _fxdata > 0 then begin {Arpeggio}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].arp1 := _fxdata shr 4;
- channels[chn].arp2 := _fxdata and 15;
- channels[chn].arp_cnt := 0;
- end;
- 1 : begin {port up}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].start_fx := 2;
- end;
- 2 : begin {port down}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].start_fx := 2;
- end;
- 3 : begin {port to}
- channels[chn].fx := _fx;
- if _fxdata > 0 then begin
- channels[chn].fxdata := _fxdata;
- channels[chn].fx_sl2 := _fxdata;
- end
- else channels[chn].fxdata := channels[chn].fx_sl2;
- channels[chn].start_fx := 2;
- end;
- 4 : begin {vibrato}
- channels[chn].fx := _fx;
- b := _fxdata and 15;
- if b = 0 then b := channels[chn].fx_vib and 15;
- w := b;
- b := _fxdata shr 4;
- if b = 0 then b := channels[chn].fx_vib shr 4;
- w := w or (b shl 4);
- b := w;
- channels[chn].fxdata := b;
- channels[chn].fx_vib := b;
- end;
- 5 : begin {port to & vol slide}
- channels[chn].fx := _fx;
- if _fxdata and 15 > 0 then
- _fxdata := _fxdata and 15; {if both ways, then slide down}
- channels[chn].fxdata := _fxdata;
- end;
- 6 : begin {Vibrato & vol slide}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- end;
- 7 : begin {Tremolo}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- end;
- 8 : begin {Set panning}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- end;
- 9 : begin {set sample offset}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- w := _fxdata * 256;
- b := channels[chn].sample;
- if channels[chn].on = 1 then gussetofs(chn+1,gus_addr[b]+w);
- end;
- $a : begin {volume slide}
- channels[chn].fx := _fx;
- if _fxdata and 15 > 0 then
- _fxdata := _fxdata and 15; {if both ways, then slide up}
- channels[chn].fxdata := _fxdata;
- channels[chn].start_fx := 2;
- end;
- $b : begin {position jump}
- if _fxdata < max_ptn then begin
- new_ptn := _fxdata;
- new_row := 0;
- jump := 1;
- end;
- end;
- $c : begin {Set volume}
- if _fxdata > 64 then _fxdata := 64;
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].vol := _fxdata;
- channels[chn].bar := _fxdata;
- w := gusvol[_fxdata {* main_vol}]*amp_vol;
- if channels[chn].on = 1 then gussetvolume(chn+1,w);
- end;
- $d : begin {break pattern}
- new_ptn := cur_ptn;
- inc(new_ptn);
- new_row := ((_fxdata and $f0) shr 4)*10+_fxdata and 15;
- jump := 1;
- end;
- $e : begin {extended effect}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- _efx := _fxdata shr 4;
- _efxdata := _fxdata and 15;
- case _efx of
- 1 : begin
- per := channels[chn].per;
- inc(per,_efxdata);
- if per > max_per then per := max_per;
- channels[chn].per := per;
- w := periods[channels[chn].per];
- gussetfreq(chn+1,w);
- end;
- 2 : begin
- per := channels[chn].per;
- dec(per,_efxdata);
- if per < min_per then per := min_per;
- channels[chn].per := per;
- w := periods[channels[chn].per];
- gussetfreq(chn+1,w);
- end;
- 4 : begin {set vibrato waveform}
- channels[chn].vib_wave := _efxdata;
- end;
- 5 : begin {set finetune}
- samples[channels[chn].sample].ftune := _efxdata;
- end;
- 8 : begin {set mtm-pan}
- channels[chn].pan := _efxdata;
- gussetbalance(chn+1,_efxdata);
- end;
- 9 : if _efxdata > 0 then begin {retrigger}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].trig_cnt := _efxdata;
- end;
- $a : begin {fine vol slide up}
- b := channels[chn].vol;
- inc(b,_efxdata);
- if b > 64 then b := 64;
- channels[chn].vol := b;
- w := gusvol[b{*main_vol}]*amp_vol;
- if channels[chn].on = 1 then gussetvolume(chn+1,w);
- channels[chn].bar := b;
- end;
- $b : begin {fine vol slide down}
- b := channels[chn].vol;
- dec(b,_efxdata);
- if b > 128 then b := 0;
- channels[chn].vol := b;
- w := gusvol[b{*main_vol}]*amp_vol;
- if channels[chn].on = 1 then gussetvolume(chn+1,w);
- channels[chn].bar := b;
- end;
- $c : begin {cut note}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- end;
- $d : if _efxdata > 0 then begin
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- channels[chn].start_fx := 1+_efxdata;
- end
- else channels[chn].fx := 255;
- end;
- end;
- $f : begin {set speed}
- channels[chn].fx := _fx;
- channels[chn].fxdata := _fxdata;
- if (_fxdata <= 32) or vblank then begin {SPEED not tempo}
- nspeed := _fxdata;
- speed := _fxdata;
- end
- else begin
- tempo := _fxdata;
- if tempo < 50 then tempo := 50;
- int_rate := 1193182 div (tempo*4 div 10);
- set_timer(int_rate);
- end;
- end
- else begin
- channels[chn].fx := 255;
- channels[chn].fxdata := 0;
- end;
- end;
- end
- else channels[chn].no_fx := 0;
- end;
-
- procedure do_fx;
- var
- chn : byte;
- _fx,_fxdata : byte;
- _efx,_efxdata : byte;
- per : word;
- b : byte;
- s : shortint;
- w : word;
-
- begin
- for chn := 0 to header.chns-1 do if channels[chn].on = 1 then begin
- if channels[chn].start_fx > 0 then dec(channels[chn].start_fx);
- _fx := channels[chn].fx;
- _fxdata := channels[chn].fxdata;
- if (channels[chn].on = 1) and (channels[chn].start_fx = 0)
- then case _fx of
- 0 : with channels[chn] do begin
- case channels[chn].arp_cnt mod 3 of
- 0 : gussetfreq(chn+1,
- periods[per_table[samples[sample].ftune,note]]);
- 1 : gussetfreq(chn+1,
- periods[per_table[samples[sample].ftune,note+arp1]]);
- 2 : gussetfreq(chn+1,
- periods[per_table[samples[sample].ftune,note+arp2]]);
- end;
- inc(arp_cnt);
- end;
- 1 : begin {port up}
- per := channels[chn].per;
- dec(per,_fxdata);
- if per < min_per then per := min_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end;
- 2 : begin {port down}
- per := channels[chn].per;
- inc(per,_fxdata);
- if per > max_per then per := max_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end;
- 3 : begin {Port to}
- if channels[chn].per < channels[chn].dper then begin
- w := channels[chn].dper;
- per := channels[chn].per;
- inc(per,channels[chn].fx_sl2);
- if per > w then per := w;
- if per > max_per then per := max_per;
- if per < min_per then per := min_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end
- else begin
- w := channels[chn].dper;
- per := channels[chn].per;
- if per-channels[chn].fx_sl2 > per then per := min_per
- else dec(per,channels[chn].fx_sl2);
- if per < w then per := w;
- if per < min_per then per := min_per;
- if per > max_per then per := max_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end;
- end;
- 4 : begin
- _fxdata := channels[chn].fx_vib;
- b := _fxdata and 15;
- s := vib_tbl[channels[chn].vib_wave,channels[chn].vib_cnt];
- s := (s * b) div 64;
- w := channels[chn].per+s;
- if w > max_per then w := max_per;
- if w < min_per then w := min_per;
- b := _fxdata shr 4;
- gussetfreq(chn+1,periods[w]);
- inc(channels[chn].vib_cnt,b);
- if channels[chn].vib_cnt > 63 then
- channels[chn].vib_cnt := channels[chn].vib_cnt - 64;
- end;
- 5 : begin
- {volume slide}
- if _fxdata and 15 > 0 then begin {slide down}
- b := channels[chn].vol;
- if b-_fxdata >= 0 then dec(b,_fxdata)
- else b := 0;
- if b > 128 then b := 0;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b {* main_vol}]*amp_vol;
- gussetvolume(chn+1,w);
- end
- else begin {slide up}
- b := channels[chn].vol;
- inc(b,_fxdata shr 4);
- if b > 64 then b := 64;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b {* main_vol}]*amp_vol;
- gussetvolume(chn+1,w);
- end;
- _fxdata := channels[chn].fx_sl2;
- if channels[chn].per < channels[chn].dper then begin {port to}
- w := channels[chn].dper;
- per := channels[chn].per;
- inc(per,_fxdata);
- if per > w then per := w;
- if per > max_per then per := max_per;
- if per < min_per then per := min_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end
- else begin
- w := channels[chn].dper;
- per := channels[chn].per;
- if per-_fxdata > per then per := min_per
- else dec(per,_fxdata);
- if per < w then per := w;
- if per < min_per then per := min_per;
- if per > max_per then per := max_per;
- channels[chn].per := per;
- gussetfreq(chn+1,periods[per]);
- end;
- end;
- 6 : begin
- begin
- b := channels[chn].fx_vib and 15;
- s := vib_tbl[channels[chn].vib_wave,channels[chn].vib_cnt];
- s := (s * b) div 64;
- w := channels[chn].per+s;
- if w > max_per then w := max_per;
- if w < min_per then w := min_per;
- b := channels[chn].fx_vib shr 4;
- gussetfreq(chn+1,periods[w]);
- inc(channels[chn].vib_cnt,b);
- if channels[chn].vib_cnt > 63 then
- channels[chn].vib_cnt := channels[chn].vib_cnt - 64;
- end;
- {volume slide}
- if _fxdata and 15 > 0 then begin {slide down}
- b := channels[chn].vol;
- if b-_fxdata >= 0 then dec(b,_fxdata)
- else b := 0;
- if b > 128 then b := 0;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b {* main_vol}]*amp_vol;
- gussetvolume(chn+1,w);
- end
- else begin {slide up}
- b := channels[chn].vol;
- inc(b,_fxdata shr 4);
- if b > 64 then b := 64;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b {* main_vol}]*amp_vol;
- gussetvolume(chn+1,w);
- end;
- end;
- $a : begin {volume slide}
- if _fxdata and 15 > 0 then begin {slide down}
- b := channels[chn].vol;
- if b < (_fxdata and 15) then b := 0
- else dec(b,_fxdata and 15);
- if b > 64 then b := 0;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b]*amp_vol;
- gussetvolume(chn+1,w);
- end
- else begin {slide up}
- b := channels[chn].vol;
- inc(b,_fxdata shr 4);
- if b > 64 then b := 64;
- channels[chn].vol := b;
- channels[chn].bar := b;
- w := gusvol[b {* main_vol}]*amp_vol;
- gussetvolume(chn+1,w);
- end;
- end;
- $e : begin
- _efx := _fxdata shr 4;
- _efxdata := _fxdata and 15;
- case _efx of
- 9 : begin
- b := channels[chn].sample;
- dec(channels[chn].trig_cnt);
- if channels[chn].trig_cnt = 0 then begin
- gussetofs(chn+1,gus_addr[b]+2);
- channels[chn].trig_cnt := _efxdata;
- end;
- end;
- $c : if _efxdata = 0 then begin
- gussetvolume(chn+1,0);
- end
- else begin
- dec(_efxdata);
- b := _fxdata;
- b := b and $f0;
- b := b or _efxdata;
- channels[chn].fxdata := b;
- end;
- $d : begin
- w := channels[chn].sample;
- if channels[chn].on = 1 then begin
- channels[chn].hit := 1;
- gussetbalance(chn+1,channels[chn].pan);
- if (samples[w].loopend > 2) then
- gusplayall(chn+1,8,gus_addr[w]+2,
- gus_addr[w]+samples[w].loopstart,
- gus_addr[w]+samples[w].loopend,
- periods[channels[chn].per],
- gusvol[channels[chn].vol]*amp_vol)
- else gusplayall(chn+1,0,gus_addr[w]+2,
- gus_addr[w],
- gus_addr[w]+samples[w].length+1,
- periods[channels[chn].per],
- gusvol[channels[chn].vol]*amp_vol);
- end;
- end;
- end;
- end;
- end;
- end;
- end;
-
- procedure updatenotes;
- var
- n : integer;
- begin
- if cur_ptn > header.length-1 then new_ptn := 0;
- cur_ptn := new_ptn;
- cur_row := new_row;
- if (cur_tick >= speed) and (speed > 0) then begin
- speed := nspeed;
- cur_tick := 0;
- if jump = 0 then inc(cur_row);
- if cur_row > 63 then begin
- inc(cur_ptn);
- cur_row := 0;
- if cur_ptn > header.length-1 then begin
- new_ptn := 0;
- cur_ptn := 0;
- end;
- end;
- end;
- for n := 0 to maxchn-1 do begin
- if channels[n].bar > 1 then dec(channels[n].bar,2)
- else channels[n].bar := 0;
- end;
- new_ptn := cur_ptn;
- new_row := cur_row;
- if speed > 0 then begin
- inc(cur_tick);
- if cur_tick = 1 then begin
- get_notes;
- if port[$3da] and 8 = 8 then vrt_flag := 1;
- get_fx;
- end;
- if port[$3da] and 8 = 8 then vrt_flag := 1;
- do_fx;
- if port[$3da] and 8 = 8 then vrt_flag := 1;
- end;
- end;
-
- procedure modint; interrupt;
- {This happens bpm*4/10 times per second (50hz if vblank).}
- begin
- asm sti end;
- if port[$3da] and 8 = 8 then vrt_flag := 1;
- inc(time_counter2);
- updatenotes;
- o_int_tick := int_tick;
- int_tick := int_tick + int_rate;
- if o_int_tick > int_tick then begin
- inc(time_counter);
- asm
- cli
- pushf
- call oldint
- end;
- end
- else
- asm
- mov al,20h
- out 20h,al {send EOI}
- end;
- end;
-
- {$s+}
- procedure load_MOD(s : string;debug : boolean);
- var
- f : file;
-
- procedure set_up_modheader;
- var
- chn : integer;
- begin
- header.samples := 31;
- header.name[0] := #20;
- move(misc_buf[0],header.name[1],20);
- header.tag := ' ';
- move(misc_buf[1080],header.tag,4);
- chn := maxchn;
- if header.tag = 'M.K.' then chn := 4
- else if header.tag = 'M!K!' then chn := 4
- else if header.tag = '6CHN' then chn := 6
- else if header.tag = '8CHN' then chn := 8
- else if header.tag = '12CH' then chn := 12
- else begin
- header.samples := 15;
- chn := 4;
- end;
- if chn > maxchn then begin
- mod_error := 1;
- exit;
- end;
- if header.samples = 15 then begin
- move(misc_buf[472],orders[0],128);
- seek(f,600);
- header.length := misc_buf[470];
- header.chns := 4;
- end else begin
- header.length := misc_buf[950];
- move(misc_buf[952],orders[0],128);
- if debug then writeln('Tag: ',header.tag);
- end;
- header.chns := chn;
- end;
-
- procedure mod_sample_info;
- var
- n : integer;
- maxi : integer;
- begin
- for n := 0 to 31 do begin
- fillchar(samples[n].name,22,0);
- samples[n].length := 0;
- samples[n].ftune := 0;
- samples[n].volume := 0;
- samples[n].loopstart := 0;
- samples[n].loopend := 0;
- end;
- for n := 1 to header.samples do begin
- move(misc_buf[(n-1)*30+20],samples[n].name[1],22);
- samples[n].name[23] := #0;
- samples[n].length := 2*swap(misc_buf2^[(n-1)*15+21]); {n*30+42}
- samples[n].ftune := misc_buf[(n-1)*30+44];
- samples[n].volume := misc_buf[(n-1)*30+45];
- samples[n].loopstart := 2*swap(misc_buf2^[(n-1)*15+23]); {n*30+46}
- samples[n].loopend := 2*swap(misc_buf2^[(n-1)*15+24]); {n*30+48}
- if samples[n].loopend < 3 then begin
- samples[n].loopend := 0;
- samples[n].loopstart := 0;
- end;
- inc(samples[n].loopend,samples[n].loopstart);
- if samples[n].loopend > samples[n].length then
- samples[n].loopend := samples[n].length;
- end;
- end;
-
- procedure read_ptn(n : word);
- var
- row,note : integer;
- w,w2,i : word;
- b : byte;
- mchn : byte;
-
- begin
- mchn := header.chns;
- blockread(f,misc_buf,256*mchn);
- for row := 0 to 63 do
- for note := 0 to mchn-1 do begin
- w := misc_buf2^[row*(2*mchn)+note*2];
- w2 := misc_buf2^[row*(2*mchn)+note*2+1];
- asm
- mov cx,w
- and cl,15
- xchg cl,ch
- and cx,0fffh
- mov i,cx
- end;
- patterns[n]^[row,note].per := i;
- asm
- mov al,byte ptr w2
- shr al,4
- mov ah,byte ptr w
- and ah,11110000b
- or al,ah
- xor ah,ah
- mov i,ax
- end;
- patterns[n]^[row][note].sample := i;
- patterns[n]^[row][note].fx := lo(w2) and 15;
- patterns[n]^[row][note].fxdata := hi(w2);
- i := patterns[n]^[row,note].per;
- w := 0;
- b := 0;
- while b = 0 do begin
- inc(w);
- if (w > 48) or (i = per_table[0,w]) then b := 1;
- end;
- if w <= 48 then patterns[n]^[row,note].note := w
- else patterns[n]^[row,note].note := 0;
- end;
- end;
-
- procedure load_patterns;
- var
- num_ptn : longint;
- n : word;
- m_ptn : integer;
- begin
- if debug then write('Loading patterns');
- num_ptn := 0;
- for n := 0 to 127 do if orders[n] > num_ptn then begin
- if orders[n] > 127 then begin
- mod_error := 2;
- exit;
- end else num_ptn := orders[n];
- end;
- max_ptn := num_ptn+1;
- for n := 0 to max_ptn-1 do begin
- if maxavail < 256*header.chns then begin
- mod_error := 3; {if error then release memory allocated}
- if n >= max_ptn-2 then for n := 0 to max_ptn-2 do dispose(patterns[n]);
- exit;
- end;
- if debug then write('.');
- new(patterns[n]);
- read_ptn(n);
- end;
- if debug then writeln;
- end;
-
- procedure load2gus(len : word);
- var
- {n : word;
- addlo,addhi : word;}
- l : longint;
-
- begin
- l := top_addr;
- asm
- mov di,len
- mov si,offset misc_buf
- @@1:
- {AddLo := L AND $FFFF;
- AddHi := longint(L and $ff0000) shr 16;}
- mov ax,word ptr l
- mov cx,ax {cx=addlo}
- mov ax,word ptr l+2
- and ax,0ffh
- mov bx,ax {bx=addhi}
-
- mov dx,command {Port [command] := $43;}
- mov al,43h
- out dx,al
-
- mov dx,data_low {Portw[data_low] := AddLo;}
- mov ax,cx
- out dx,ax
-
- mov dx,command {Port [command] := $44;}
- mov al,44h
- out dx,al
-
- mov dx,data_high
- mov ax,bx
- out dx,ax {Port [data_high] := AddHi;}
-
- add word ptr l,1 {inc(l,1);}
- adc word ptr l+2,0
-
- mov dx,dram_io {Port [dram_io] := misc_buf[n];}
- outsb
-
- dec di
- jnz @@1
- end;
- inc(top_addr,len);
- end;
-
- procedure load_sample(num : word);
- const
- block = 4096;
- var
- w : word;
- fl,l : word;
- len : longint;
-
- begin
- if debug then write('.');
- guspoke(top_addr,0);
- inc(top_addr);
- guspoke(top_addr,0);
- inc(top_addr);
- len := samples[num].length+top_addr;
- if (len > gus_bank+$40000) and (top_addr < gus_bank+$40000) then begin
- gus_bank := gus_bank+$40000;
- top_addr := gus_bank;
- end;
-
- samples[num].addr := top_addr;
- gus_addr[num] := top_addr;
- if samples[num].length < 1 then exit;
- {blockread(f,w,2);} {read amiga repeat bytes}
- fl := (samples[num].length) div block;
- l := (samples[num].length) mod block;
- if fl > 0 then for w := 1 to fl do begin
- blockread(f,misc_buf,block);
- load2gus(block); {load in 4kb blocks}
- end;
- if l > 0 then begin
- blockread(f,misc_buf,l);
- load2gus(l); {load remainder}
- end;
- if samples[num].loopend > 2 then begin
- guspoke(top_addr,guspeek(gus_addr[num]+samples[num].loopstart));
- guspoke(gus_addr[num]+samples[num].loopend+1,
- guspeek(gus_addr[num]+samples[num].loopstart));
- inc(top_addr);
- end;
- end;
-
- var
- i : integer;
- l : longint;
-
- begin
- gus_bank := 0;
- assign(f,s);
- {$i-}
- reset(f,1);
- blockread(f,misc_buf,1084); {read module header}
- i := ioresult;
- if i <> 0 then begin
- mod_error := 2;
- exit;
- end;
- set_up_modheader;
- if mod_error <> 0 then exit;
- mod_sample_info;
- load_patterns;
- if mod_error <> 0 then exit;
- if debug then write('Loading samples');
- for i := 0 to 31 do load_sample(i);
- if debug then writeln;
- close(f);
- {$i+}
- end;
-
- procedure free_mod;
- var
- n,i : word;
- begin
- for n := max_ptn-1 downto 0 do dispose(patterns[n]);
- top_addr := 16;
- for n := 0 to 31 do with samples[n] do begin
- addr := 0;
- for i := 0 to sizeof(name) do name[i] := #0;
- length := 0;
- loopstart := 0;
- loopend := 0;
- ftune := 0;
- volume := 0;
- end;
- gus_bank := 0;
- end;
-
- procedure init_mod;
- var
- n,i : integer;
- l : longint;
-
- begin
- vrt_flag := 0;
- misc_buf2 := @misc_buf;
- for n := 10 to 1050 do begin
- {gusperiod:=586580935 div (amigaperiod * (divisor div 100 shl 4))}
- {divisor = 44100}
- {l := 7093789 div (n*2);
- l := l div 40;}
- l := n;
- l := 586580935 div (l * 7056);
- periods[n] := l;
- {hz = 7093789.2/(per*2)}
- end;
- for n := 0 to 255 do orders[n] := 0;
- for n := 0 to maxchn-1 do begin
- channels[n].vol := 64;
- channels[n].per := 0;
- channels[n].dper := 0;
- channels[n].sample := 0;
- channels[n].pan := 7; {middle}
- channels[n].note := 0;
- end;
- for n := 0 to 31 do with samples[n] do begin
- addr := 0;
- for i := 0 to sizeof(name) do name[i] := #0;
- length := 0;
- loopstart := 0;
- loopend := 0;
- ftune := 0;
- volume := 0;
- end;
- for n := 0 to 128 do patterns[n] := nil;
- for n := 1 to 14 do gussetvolume(n,0);
- for n := 1 to 14 do gusstopvoice(n);
- cur_ptn := 0;
- cur_row := 0;
- new_ptn := 0;
- new_row := 0;
- cur_tick := 0;
- for n := 0 to 31 do guspoke(n,0);
- top_addr := 16;
- gus_bank := 0;
- vblank := false;
- getintvec(8,@oldint);
- end;
-
- procedure set_timer(ticks : word);
- begin
- asm cli end;
- port[$43] := $36;
- port[$40] := lo(ticks);
- port[$40] := hi(ticks);
- asm sti end;
- end;
-
- procedure stop_playing;
- var
- n : integer;
- begin
- int_rate := 65535;
- set_timer(65535);
- setintvec(8,@oldint);
- for n := 1 to maxchn do GusStopVoice(n);
- end;
-
- procedure start_playing;
- var
- n : integer;
- begin
- for n := 0 to maxchn-1 do begin
- channels[n].vol := 0;
- channels[n].per := 428;
- channels[n].sample := 0;
- channels[n].pan := 7; {middle}
- channels[n].on := 1;
- channels[n].dper := 428;
- channels[n].bar := 0;
- channels[n].fx := 255;
- channels[n].fxdata := 0;
- channels[n].fx_sl2 := 0;
- channels[n].fx_vib := 0;
- channels[n].vib_cnt := 0;
- channels[n].vib_wave := 0;
- channels[n].note := 0;
- channels[n].hit := 0;
- channels[n].no_fx := 0;
- channels[n].start_fx := 0;
- channels[n].arp1 := 0;
- channels[n].arp2 := 0;
- channels[n].arp_cnt := 0;
- end;
- speed := 6;
- nspeed := 6;
- tempo := 125;
- channels[0].pan := 7-def_pan;
- channels[1].pan := 7+def_pan;
- channels[2].pan := 7+def_pan;
- channels[3].pan := 7-def_pan;
- if maxchn > 4 then for n := 4 to maxchn-1 do
- channels[n].pan := channels[n-4].pan;
- if maxchn > 8 then for n := 8 to maxchn-1 do
- channels[n].pan := channels[n-8].pan;
- jump := 0;
- int_tick := 0;
- cur_ptn := 0;
- cur_row := 0;
- new_ptn := 0;
- new_row := 0;
- cur_tick := 0;
- time_counter := 0;
- time_counter2 := 0;
- asm cli end;
- setintvec(8,@modint);
- int_rate := 1193182 div 50;
- set_timer(int_rate);
- asm sti end;
- end;
-
- begin
- end.
-